<?php

class GList
{

    const EOL = "\n";

    private $url = null;

    private $source = false;

    private $rows = false;

    public function __construct($url)
    {
        if (!empty($url))
            $this->url = $url;
    }

    public function getPath()
    {
        return Brothen::mkPath('temp/glist_src.php');
    }

    public function getUrl()
    {
        if (is_array($this->url))
            return call_user_func_array([Util::class, 'mkUrl'], $this->url);
        else
            return Util::mkUrl($this->url);
    }

    public function updateSource()
    {
        $this->source = file_get_contents($this->getUrl());
        $this->source = base64_decode($this->source);
        $this->dumpSource($this->source);
    }

    public function dumpSource($source)
    {
        if (!empty($source)) {
            $path = $this->getPath();
            $export = var_export($source, true);
            file_put_contents($path, "<?php\r\nreturn {$export};\r\n");
        }
        return $this;
    }

    public function loadSource()
    {
        $path = $this->getPath();
        if (is_file($path) && is_readable($path)) {
            $this->source = require $path;
        } else {
            $this->updateSource();
        }
        return $this->source;
    }

    public function getSource()
    {
        if ($this->source === false) {
            $this->loadSource();
        }
        return $this->source;
    }

    public function parseSource($source)
    {
        if (preg_match_all('#^[^\!\[\r\n].+$#m', $source, $rows)) {
            return $rows[0];
        }
        return array();
    }


    public function getRows()
    {
        if ($this->rows === false) {
            $path = Brothen::mkPath('temp/glist_src_rows.php');
            if (is_file($path) && is_readable($path)) {
                $this->rows = require $path;
            } else {
                $this->rows = $this->parseSource($this->getSource());
                $export = var_export($this->rows, true);
                file_put_contents($path, "<?php\r\nreturn {$export};\r\n");
            }
        }
        return $this->rows;
    }

    public function concatData($raw, $explain, array $data) {
        if (!empty($data)) {
            $raw[] = '! ' . $explain;
            $raw[] = implode(self::EOL, $data);
        }
        return $raw;
    }

    public function getOutputData($encode = true)
    {
        $data = [
            '['. Brothen::getConfig('name') . ']',
            implode(self::EOL, $this->getRows()),
        ];
        $data = $this->concatData($data, 'white list', Brothen::getConfig('white_list', array()));
        $data = $this->concatData($data, 'through list', Brothen::getConfig('through_list', array()));
        $temp = implode(self::EOL, $data);
        $checksum = $this->checksum($temp);
        $data[0] .= self::EOL . "! Checksum: {$checksum}";
        $data = implode(self::EOL, $data);
        if ($encode) {
            $data = base64_encode($data);
            $data = chunk_split($data, 64, self::EOL);
        }
        return $data;
    }

    function checksum($data) {
        $replaceCheckSumRegex = '/^.*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n/mi';

        $checksumText = $data;
        $checksumText = preg_replace($replaceCheckSumRegex, '', $checksumText);
        $checksumText = preg_replace('/\r/', '', $checksumText);
        $checksumText = preg_replace('/\n+/', "\n", $checksumText);
        $md5 = md5($checksumText, true);
        $base64 = base64_encode($md5);
        $result = str_replace(array('=', '/'), '', $base64);

        return $result;
    }
}